package cn.aitrox.ry.common.dao.impl;

import cn.aitrox.ry.common.dao.BaseDao;
import cn.aitrox.ry.common.dao.MapperSqlCallback;
import cn.aitrox.ry.common.exception.BaseDBServiceException;
import com.github.abel533.entity.Example;
import com.github.abel533.mapper.Mapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据库常用操作api
 *
 * @param <T>
 */
public abstract class BaseDaoImpl<T> implements BaseDao<T> {

    private static final String SERIS_FIELD_NAME = "serialVersionUID";

    @Autowired(required = false)
    public Mapper<T> mapper;

    public String getPrimaryKey() {
        return "id";
    }

    public T findById(Object id) {
        return mapper.selectByPrimaryKey(id);
    }

    public List<T> findByIds(Object[] ids, String orderBy) {
        if (null == ids || ids.length == 0) {
            return new ArrayList<>();
        }
        Example example = this.exampleForIds(Arrays.asList(ids), orderBy);
        return mapper.selectByExample(example);
    }

    /**
     * 条件查询 注意：如果t中的属性为null，该属性将不会作为And条件，如果属性都为null，将查询所有
     *
     * @param t
     * @return
     */
    public List<T> findByCondition(T t, String orderBy) {
        try {
            if (StringUtils.isEmpty(orderBy)) {
                return mapper.select(t);
            } else {
                Example example = new Example(t.getClass());
                example.setOrderByClause(orderBy);
                Map<String, Object> map = this.refelectFieldNameValueNotNull(t);
                Example.Criteria criteria = example.createCriteria();
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    criteria.andEqualTo(entry.getKey(), entry.getValue());
                }
                return mapper.selectByExample(example);
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public int findCountByCondition(T t) {
        return mapper.selectCount(t);
    }

    public int findCount() {
        return mapper.selectCount(null);
    }

    public List<T> findAll() {
        return mapper.select(null);
    }

    public List<T> findAllOrderBy(String orderBy) {
        ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
        Class clazz = (Class<T>) parameterizedType.getActualTypeArguments()[0];
        if (StringUtils.isEmpty(orderBy)) {
            return mapper.select(null);
        } else {
            Example example = new Example(clazz);
            example.setOrderByClause(orderBy);
            return mapper.selectByExample(example);
        }
    }

    public T findOne(T t) {
        return mapper.selectOne(t);
    }

    /**
     * 分页查询 PageInfo中的total是数据总数 pages是总页数 list是当前页数据
     *
     * @param page
     * @param pageSize
     * @param t
     * @return
     */
    public PageInfo<T> searchByCondition(Integer page, Integer pageSize, String orderBy, T t) {
        PageHelper.startPage(page, pageSize, true);
        if (StringUtils.isNotEmpty(orderBy)) {
            PageHelper.orderBy(orderBy);
        }
        PageInfo<T> pageInfo = new PageInfo<>(mapper.select(t));
        if (pageInfo.getPages() < page) {
            pageInfo.setList(new ArrayList<T>());
        }
        return pageInfo;
    }

    public PageInfo<T> search(Integer page, Integer pageSize, String orderBy) {
        PageHelper.startPage(page, pageSize, true);
        if (StringUtils.isNotEmpty(orderBy)) {
            PageHelper.orderBy(orderBy);
        }
        PageInfo<T> pageInfo = new PageInfo<>(mapper.select(null));
        if (pageInfo.getPages() < page) {
            pageInfo.setList(new ArrayList<T>());
        }
        return pageInfo;
    }

    public PageInfo<T> searchByCustom(Integer page, Integer pageSize, MapperSqlCallback<T> callback) {
        PageHelper.startPage(page, pageSize, true);
        PageInfo<T> pageInfo = new PageInfo<>(callback.invoke());
        if (pageInfo.getPages() < page) {
            pageInfo.setList(new ArrayList<T>());
        }
        return pageInfo;
    }

    public PageInfo<T> searchByCustom(Integer page, Integer pageSize, String orderBy, MapperSqlCallback<T> callback) {
        PageHelper.startPage(page, pageSize, true);
        if (StringUtils.isNotEmpty(orderBy)) {
            PageHelper.orderBy(orderBy);
        }
        PageInfo<T> pageInfo = new PageInfo<>(callback.invoke());
        if (pageInfo.getPages() < page) {
            pageInfo.setList(new ArrayList<T>());
        }
        return pageInfo;
    }

    public <K> PageInfo<K> searchResultByCustom(Integer page, Integer pageSize, MapperSqlCallback<K> callback) {
        PageHelper.startPage(page, pageSize, true);
        PageInfo<K> pageInfo = new PageInfo<K>(callback.invoke());
        if (pageInfo.getPages() < page) {
            pageInfo.setList(new ArrayList<K>());
        }
        return pageInfo;
    }

    public <K> PageInfo<K> searchResultByCustom(Integer page, Integer pageSize, String orderBy, MapperSqlCallback<K> callback) {
        PageHelper.startPage(page, pageSize, true);
        if (StringUtils.isNotEmpty(orderBy)) {
            PageHelper.orderBy(orderBy);
        }
        PageInfo<K> pageInfo = new PageInfo<>(callback.invoke());
        if (pageInfo.getPages() < page) {
            pageInfo.setList(new ArrayList<K>());
        }
        return pageInfo;
    }

    /**
     * 保存所有属性
     *
     * @param t
     * @return
     */
    public int insert(T t) {
        return mapper.insert(t);
    }

    /**
     * 保存不为null的属性
     *
     * @param t
     * @return
     */
    public int insertSelective(T t) {
        return mapper.insertSelective(t);
    }

    public int updateById(T t) {
        return mapper.updateByPrimaryKey(t);
    }

    public int updateByIdSelective(T t) {
        return mapper.updateByPrimaryKeySelective(t);
    }

    public int updateByIds(T t, Object[] ids) {
        if (null == ids || ids.length == 0) {
            return 0;
        }
        Example example = this.exampleForIds(Arrays.asList(ids), null);
        return mapper.updateByExample(t, example);
    }

    public int updateByIdsSelective(T t, Object[] ids) {
        if (null == ids || ids.length == 0) {
            return 0;
        }
        Example example = this.exampleForIds(Arrays.asList(ids), null);
        return mapper.updateByExampleSelective(t, example);
    }

    public int deleteById(Object id) {
        return mapper.deleteByPrimaryKey(id);
    }

    public int deleteByIds(Object[] ids) {
        if (null == ids || ids.length == 0) {
            return 0;
        }
        Example example = this.exampleForIds(Arrays.asList(ids), null);
        return mapper.deleteByExample(example);
    }

    public void deleteAll() {
        mapper.delete(null);
    }

    public void batchInsert(List<T> objList, int insertCountOfIter, MapperSqlCallback<T> callback) {
        if (null == objList || objList.size() == 0) {
            return;
        }
        List<T> list = new ArrayList<T>();
        for (int i = 0; i < objList.size(); i++) {
            if (i != 0 && (i % insertCountOfIter) == 0) {
                callback.batchInsert(list);
                list.clear();
                list.add(objList.get(i));
            } else {
                list.add(objList.get(i));
            }
        }
        if (null != list && list.size() > 0) {
            callback.batchInsert(list);
        }
    }

    private Map<String, Object> refelectFieldNameValueNotNull(Object obj) throws IllegalAccessException {
        HashMap<String, Object> map = new HashMap<String, Object>();
        if (obj == null) {
            return map;
        }
        Field[] fields = obj.getClass().getDeclaredFields();
        if (null == fields || fields.length == 0) {
            return map;
        }
        for (int i = 0; i < fields.length; i++) {
            fields[i].setAccessible(true);
            String fieldName = fields[i].getName();
            if (SERIS_FIELD_NAME.equals(fieldName)) {
                continue;
            }
            Object fieldValue = fields[i].get(obj);
            if (null != fieldValue) {
                map.put(fields[i].getName(), fieldValue);
            }
        }
        return map;
    }

    private Example exampleForIds(List<Object> ids, String orderBy) {
        if (null == this.getPrimaryKey()) {
            throw new BaseDBServiceException("no override getPrimaryKey()");
        }
        if (null == ids || ids.size() == 0) {
            throw new BaseDBServiceException("primary key values is empty");
        }
        Example example = new Example(this.getEntityClass());
        example.setOrderByClause(orderBy);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn(this.getPrimaryKey(), ids);
        return example;
    }

    private Class getEntityClass() {
        // 获取子类的class
        Class<?> clazz = this.getClass();
        Class<?> entityClass = null;
        // 获取其泛化的超类
        Type genericSuperclass = clazz.getGenericSuperclass();

        // 如果子类实现了参数化接口
        if (genericSuperclass instanceof ParameterizedType) {
            // 获取所有的参数化的类型
            Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
            if (actualTypeArguments != null && actualTypeArguments.length > 0) {
                entityClass = (Class<?>) actualTypeArguments[0];
            }
        }
        return entityClass;
    }
}
